HEAD ======= >>>>>>> ad0bc60fadc363530d65adc66a558bb30ba913a4
Looking for a new romance book? Want to get into some classics? Looking to read another book by your favorite author? Fear not! You can find book recommendations right here. Search by your favorite author or genre and your preferred rating.
Have fun reading!
<<<<<<< HEADlibrary(tidyverse)
library(shiny)
library(bslib)
library(dplyr)
=======
library(tidyverse)
## ── Attaching core tidyverse packages ─────────────────
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.1 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ──────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(shiny)
##
## Attaching package: 'shiny'
##
## The following object is masked _by_ '.GlobalEnv':
##
## tags
library(bslib)
##
## Attaching package: 'bslib'
##
## The following object is masked from 'package:utils':
##
## page
library(dplyr)
>>>>>>> ad0bc60fadc363530d65adc66a558bb30ba913a4
knitr::opts_chunk$set(echo = TRUE)
books = read_csv("./Data/books_with_tags.csv")
## Rows: 9300 Columns: 20
<<<<<<< HEAD
## ── Column specification ──────────────────────────────────────────────────────────────────────────────────────────
## Delimiter: ","
## chr (9): isbn, authors, title, image_url, top_1, top_2, top_3, top_4, top_5
## dbl (11): book_id, goodreads_book_id, average_rating, ratings_count, work_ratings_count, work_text_reviews_cou...
=======
## ── Column specification ──────────────────────────────
## Delimiter: ","
## chr (9): isbn, authors, title, image_url, top_1, top_2, top_3, top_4, top_5
## dbl (11): book_id, goodreads_book_id, average_rating, ratings_count, work_ra...
>>>>>>> ad0bc60fadc363530d65adc66a558bb30ba913a4
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
books_clean = books |>
select(-isbn,-ratings_count,-work_ratings_count,-work_text_reviews_count)
books_rate <- books_clean |>
mutate(average_rating = round(average_rating*2)/2)
authors <- unique(books_rate$authors)
ui <- fluidPage(
<<<<<<< HEAD
=======
>>>>>>> ad0bc60fadc363530d65adc66a558bb30ba913a4
selectInput("search_by",
label = "Search by:",
choices = c("Select", "Author", "Genre")),
conditionalPanel(
condition = "input.search_by == 'Author'",
selectizeInput("authors",
label = "Start typing an author's name:",
choices = authors,
options = list(
placeholder = 'Select an author...',
create = FALSE,
maxItems = 1,
highlight = TRUE))
),
conditionalPanel(
condition = "input.search_by == 'Genre'",
selectInput("search_genre",
label = "Choose Genre(s):",
choices = unique(c(books_rate$top_1, books_rate$top_2, books_rate$top_3, books_rate$top_4, books_rate$top_5)),
multiple = TRUE)
),
conditionalPanel(
condition = "input.search_by == 'Genre' || input.search_by == 'Author'",
selectInput("average_rating",
label = "Choose Rating:",
choices = unique(books_rate$average_rating),
selected = NULL)
),
actionButton("recommend", "Get Recommendations"),
h3("Your Recommended Books:"),
uiOutput("book_list")
)
<<<<<<< HEAD
## Warning: The select input "authors" contains a large number of options; consider using server-side selectize for
## massively improved performance. See the Details section of the ?selectizeInput help topic.
## Warning: The select input "search_genre" contains a large number of options; consider using server-side selectize
## for massively improved performance. See the Details section of the ?selectizeInput help topic.
=======
## Warning: The select input "authors" contains a large number of options;
## consider using server-side selectize for massively improved performance. See
## the Details section of the ?selectizeInput help topic.
## Warning: The select input "search_genre" contains a large number of options;
## consider using server-side selectize for massively improved performance. See
## the Details section of the ?selectizeInput help topic.
>>>>>>> ad0bc60fadc363530d65adc66a558bb30ba913a4
server <- function(input, output, session) {
filtered_books <- reactive({
booktok <- books_rate
if (length(input$search_genre) > 0) {
booktok <- booktok %>%
filter(
top_1 %in% input$search_genre |
top_2 %in% input$search_genre |
top_3 %in% input$search_genre |
top_4 %in% input$search_genre |
top_5 %in% input$search_genre
)
}
if (input$search_by == "Author" && input$authors != "") {
booktok <- booktok %>% filter(authors == input$authors)
}
if (!is.null(input$average_rating) && input$average_rating != "") {
booktok <- booktok %>% filter(average_rating == as.numeric(input$average_rating))
}
booktok %>% distinct(title, .keep_all = TRUE)
})
observeEvent(input$recommend, {
output$book_list <- renderUI({
booktok <- filtered_books()
if (nrow(booktok) < 5 && !is.null(input$average_rating)) {
selected_rating <- as.numeric(input$average_rating)
lower_rating_books <- books_rate %>%
filter(average_rating == (selected_rating - 1)) %>%
distinct(title, .keep_all = TRUE)
# Only bind rows if there are books with lower rating
if (nrow(lower_rating_books) > 0) {
booktok <- bind_rows(booktok, lower_rating_books)
}
}
books_to_show <- head(booktok, 5)
if (nrow(books_to_show) > 0) {
tagList(
lapply(1:nrow(books_to_show), function(i) {
lower_rated <- books_to_show$average_rating[i] < as.numeric(input$average_rating)
div(
img(src = books_to_show$image_url[i], width = "250px", height = "300px"),
strong(books_to_show$title[i]),
if (lower_rated) {
span(style = "color: brown; font-weight: bold;", "(Rated Below Your Selection)")
},
p(paste("Rating:", books_to_show$average_rating[i]))
)
})
)
} else {
p("No books found based on your selection.")
}
})
})
}
shinyApp(ui = ui, server = server)
<<<<<<< HEAD
=======
>>>>>>> ad0bc60fadc363530d65adc66a558bb30ba913a4